﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Styx;
using Styx.CommonBot;
using Styx.CommonBot.Routines;
using Styx.Helpers;
using Styx.TreeSharp;
using Styx.WoWInternals;
using Styx.WoWInternals.WoWObjects;
using Action = Styx.TreeSharp.Action;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using Styx.Pathing;
using Styx.Common;
using System.Windows.Media;
using Styx.CommonBot.Frames;
using System.Diagnostics;


namespace Guardian
{
    public partial class Combat : CombatRoutine
    {

        public override string Name { get { return "Guardian by Pasterke"; } }
        public override WoWClass Class { get { return WoWClass.Druid; } }
        public LocalPlayer Me { get { return StyxWoW.Me; } }

        public override Composite CombatBehavior { get { return CreateCombat(); } }
        public override Composite PreCombatBuffBehavior { get { return CreatePreCombatBuffs(); } }
        public override Composite PullBehavior { get { return CreatePullBehavior(); } }
        public override Composite RestBehavior { get { return CreateRestBehavior(); } }

        public override bool WantButton { get { return true; } }
        public override void OnButtonPress()
        {
            Form1 ConfigForm = new Form1();
            ConfigForm.ShowDialog();
        }

        public string usedBot { get { return BotManager.Current.Name.ToUpper(); } }

        public override void Pulse()
        {
            try
            {
                if (Me.IsDead
                    && usedBot.Contains("QUEST") || usedBot.Contains("GRIND") || usedBot.Contains("GATHER"))
                {
                    Lua.DoString(string.Format("RunMacroText(\"{0}\")", "/script RepopMe()"));
                }
                if (!Me.Combat && (usedBot.Contains("QUEST") || usedBot.Contains("GRIND")) && Lootables.Count() >= 1)
                {
                    GetLoot();
                }
                return;
            }
            catch { }
        }

        public override void Initialize()
        {
            Lua.Events.AttachEvent("MODIFIER_STATE_CHANGED", HandleModifierStateChanged);
            EventHandlers.AttachCombatLogEvent();
        }

        public override void ShutDown()
        {
            Lua.Events.DetachEvent("MODIFIER_STATE_CHANGED", HandleModifierStateChanged);
        }

        Composite CreateRestBehavior()
        {
            return new PrioritySelector(
                EatFood(),
                Cast(HEALING_TOUCH, ret => SpellManager.HasSpell(HEALING_TOUCH) && Me.HealthPercent <= SettingsBear.myPrefs.PercentHealingTouch && !Me.HasAura("Drink") && !Me.HasAura("Food")),
                Cast(REJUVENATION, ret => SpellManager.HasSpell(REJUVENATION) && !Me.HasAura(REJUVENATION) && Me.HealthPercent <= SettingsBear.myPrefs.PercentRejuvenation && !Me.HasAura("Drink") && !Me.HasAura("Food"))
                );
        }

        Composite CreatePreCombatBuffs()
        {
            return new PrioritySelector(
                CastOnMe(MOTW, ret => CanBuffEat
                    && !Me.HasAura(MOTW) && !Me.HasAura("Blessing of Kings") && !Me.HasAura("Legacy of the Emperor")),
                new Decorator(ret => !Me.HasAura("Symbiosis") && SettingsBear.myPrefs.AutoSymbiosis, CastSymbiosis())
                );
        }

        Composite CreatePullBehavior()
        {
            return new PrioritySelector(
                new Decorator(ret => Paused, PauseCR()),
                new Decorator(ret => Me.Specialization == WoWSpec.None && !SpellManager.HasSpell("Cat Form"),
                    new PrioritySelector(
                        new Decorator(ret => gotTarget
                        && AllowFacing
                        && !Me.IsSafelyFacing(Me.CurrentTarget), FaceMyTarget()),
                    new Decorator(ret => gotTarget && AllowMovement && (Me.CurrentTarget.Distance > 35
                        || !Me.CurrentTarget.InLineOfSight), CreateMovementBehavior()),
                    new Decorator(ret => gotTarget && Me.CurrentTarget.Distance <= 35, CreateStopMovement()),
                    Cast("Moonfire", ret => gotTarget && !debuffExists("Moonfire", Me.CurrentTarget)),
                    Cast("Wrath", ret => gotTarget)
                    )),
                new Decorator(ret => Me.Specialization == WoWSpec.None && SpellManager.HasSpell("Cat Form"),
                    new PrioritySelector(
                        new Decorator(ret => gotTarget
                            && AllowFacing
                            && !Me.IsSafelyFacing(Me.CurrentTarget), FaceMyTarget()),
                        new Decorator(ret => gotTarget && AllowMovement && (Me.CurrentTarget.Distance > myRange
                            || !Me.CurrentTarget.InLineOfSight), CreateMovementBehavior()),
                        new Decorator(ret => gotTarget && Me.CurrentTarget.Distance <= myRange, CreateStopMovement()),
                        Cast("Cat Form", ret => Me.Shapeshift != ShapeshiftForm.Cat),
                        Cast("Rake", ret => gotTarget)
                        )),
                new Decorator(ret => Me.Specialization == WoWSpec.DruidGuardian,
                    new PrioritySelector(
                        Cast(BEAR_FORM, ret => SpellManager.HasSpell(BEAR_FORM)
                        && Me.Shapeshift != ShapeshiftForm.Bear),
                        new Decorator(ret => (Me.CurrentTarget == null
                            || (Me.CurrentTarget != null
                            && Me.CurrentTarget.IsDead))
                            && AllowTargeting,
                            new Action(ret => { Me.ClearTarget(); FindTarget(); return RunStatus.Failure; })),
                        new Decorator(ret => gotTarget
                            && AllowFacing
                            && !Me.IsSafelyFacing(Me.CurrentTarget), FaceMyTarget()),
                        new Decorator(ret => gotTarget && AllowMovement && (Me.CurrentTarget.Distance > myRange
                            || !Me.CurrentTarget.InLineOfSight), CreateMovementBehavior()),
                        new Decorator(ret => gotTarget && Me.CurrentTarget.Distance <= myRange, CreateStopMovement()),
                        Cast(FAERIE_SWARM, ret => gotTarget
                            && SpellManager.HasSpell(FAERIE_SWARM)
                            && GetSpellCooldown(FAERIE_SWARM).TotalSeconds < 1),
                        Cast(FAERIE_FIRE, ret => gotTarget
                            && SpellManager.HasSpell(FAERIE_FIRE)
                            && !SpellManager.HasSpell(FAERIE_SWARM)
                            && GetSpellCooldown(FAERIE_FIRE).TotalSeconds < 1),
                        Cast(GROWL, ret => gotTarget && GetSpellCooldown(GROWL).TotalSeconds < 1),
                        Cast(MAUL, ret => gotTarget && GetSpellCooldown(MAUL).TotalSeconds < 1 && Me.RagePercent >= 30),
                        Cast(MANGLE, ret => gotTarget && GetSpellCooldown(MANGLE).TotalSeconds < 1),
                        Cast(LACERATE, ret => gotTarget && GetSpellCooldown(LACERATE).TotalSeconds < 1)
                )));
        }

        Composite CreateCombat()
        {
            return new PrioritySelector(
                new Decorator(ret => Paused, PauseCR()),
                new Decorator(ret => Me.Specialization == WoWSpec.DruidGuardian,
                    new PrioritySelector(
                        Cast(BEAR_FORM, ret => SpellManager.HasSpell(BEAR_FORM)
                            && Me.Shapeshift != ShapeshiftForm.Bear),
                        Healthstone(),
                        new Decorator(ret => Me.Mounted && usedBot.Contains("QUEST"), new Action(ret => { Lua.DoString("Dismount()"); return RunStatus.Failure; })),
                        new Decorator(ret => !Me.CurrentMap.IsArena
                            && SettingsBear.myPrefs.AutoResTank
                            && (Me.CurrentMap.IsRaid || Me.CurrentMap.IsDungeon || Me.CurrentMap.IsScenario || Me.CurrentMap.IsInstance)
                            && AnyTankNearby 
                            && IsOverlayed(REBIRTH_INT) 
                            && !spellOnCooldown(REBIRTH), ResTank()),
                        new Decorator(ret => !Me.CurrentMap.IsArena
                            && SettingsBear.myPrefs.AutoResHealer
                            && (Me.CurrentMap.IsRaid || Me.CurrentMap.IsDungeon || Me.CurrentMap.IsScenario || Me.CurrentMap.IsInstance)
                            && AnyHealerNearby 
                            && IsOverlayed(REBIRTH_INT) 
                            && !spellOnCooldown(REBIRTH), ResHealer()),
                        new Decorator(ret => Me.HealthPercent >= 90
                            && (Me.CurrentMap.IsRaid || Me.CurrentMap.IsDungeon || Me.CurrentMap.IsScenario || Me.CurrentMap.IsInstance)
                            && IsOverlayed(HEALING_TOUCH_INT), HealPartyMember()),
                        CastOnMe(HEALING_TOUCH, ret => IsOverlayed(HEALING_TOUCH_INT) && buffTimeLeft(DREAM_OF_CENARIUS, Me) <= 3000),
                        new Decorator(ret => (Me.CurrentTarget == null 
                            || (Me.CurrentTarget != null 
                            && Me.CurrentTarget.IsDead))
                            && AllowTargeting,
                                new Action(ret => { Me.ClearTarget(); FindTarget(); return RunStatus.Failure; })),
                        new Decorator(ret => gotTarget && !Me.IsAutoAttacking && Me.CurrentTarget.Distance <= myRange, AutoAttack()),
                        new Decorator(ret => IsCrowdControlledPlayer(Me), RemoveRooted()),
                        new Decorator(ret => gotTarget && AllowFacing && !Me.IsSafelyFacing(Me.CurrentTarget), FaceMyTarget()),
                        new Decorator(ret => gotTarget && AllowMovement && (Me.CurrentTarget.Distance > myRange || !Me.CurrentTarget.InLineOfSight), CreateMovementBehavior()),
                        new Decorator(ret => gotTarget && AllowMovement && Me.CurrentTarget.Distance <= myRange && Me.IsMoving, CreateStopMovement()),
                        Cast("Lightning Shield", ret => gotTarget
                            && SpellManager.HasSpell("Lightning Shield")
                            && !Me.HasAura("Lightning Shield")
                            && GetSpellCooldown("Lightning Shield").TotalSeconds < 1),
                        Cast("Elusive Brew", ret => gotTarget
                            && SpellManager.HasSpell("Elusive Brew")
                            && GetSpellCooldown("Elusive Brew").TotalSeconds < 1
                            && Me.HealthPercent <= SettingsBear.myPrefs.PercentElusiveBrew),
                        Cast(FAERIE_SWARM, ret => gotTarget
                            && SpellManager.HasSpell(FAERIE_SWARM)
                            && GetSpellCooldown(FAERIE_SWARM).TotalSeconds < 1
                            && (!Me.CurrentTarget.HasAura(FAERIE_SWARM) || !Me.CurrentTarget.HasAura("Weakened Armor"))),
                        Cast(FAERIE_FIRE, ret => gotTarget
                            && SpellManager.HasSpell(FAERIE_FIRE)
                            && !SpellManager.HasSpell(FAERIE_SWARM)
                            && GetSpellCooldown(FAERIE_FIRE).TotalSeconds < 1
                            && (!Me.CurrentTarget.HasAura(FAERIE_FIRE) || !Me.CurrentTarget.HasAura("Weakened Armor"))),
                        Cast("Bone Shield", ret => SpellManager.HasSpell("Bone Shield")
                            && GetSpellCooldown("Bone Shield").TotalSeconds < 1
                            && !Me.HasAura("Bone Shield")),
                        Cast("Consecration", ret => gotTarget
                            && SpellManager.HasSpell("Consecration")
                            && GetSpellCooldown("Consecration").TotalSeconds < 1
                            && (UnfriendlyUnits.Count() > 2 || IsWoWBoss(Me.CurrentTarget))
                            && Me.CurrentTarget.IsWithinMeleeRange),
                        Cast(SKULL_BASH, ret => gotTarget
                            && SpellManager.HasSpell(SKULL_BASH)
                            && GetSpellCooldown(SKULL_BASH).TotalSeconds < 1
                            && (Me.CurrentTarget.IsCasting && Me.CanInterruptCurrentSpellCast)),
                        Cast(WAR_STOMP, ret => gotTarget
                            && SpellManager.HasSpell(WAR_STOMP)
                            && !spellOnCooldown(WAR_STOMP)
                            && (Me.CurrentTarget.IsCasting && !Me.CanInterruptCurrentSpellCast)),
                       Cast(MIGHTY_BASH, ret => gotTarget
                            && SpellManager.HasSpell(MIGHTY_BASH)
                            && !spellOnCooldown(MIGHTY_BASH)
                            && (Me.CurrentTarget.IsCasting && !Me.CanInterruptCurrentSpellCast)),
                        Cast(BARKSKIN, ret => gotTarget
                            && GetSpellCooldown(BARKSKIN).TotalSeconds < 1
                            && Me.HealthPercent <= SettingsBear.myPrefs.PercentBarkskin
                            && Me.CurrentTarget.IsWithinMeleeRange),
                        Cast(FRENZIED_REGENERATION, ret => gotTarget
                            && SpellManager.HasSpell(FRENZIED_REGENERATION)
                            && GetSpellCooldown(FRENZIED_REGENERATION).TotalSeconds < 1
                            && Me.HealthPercent <= SettingsBear.myPrefs.PercentFrenziedRegeneration),
                        Cast(SAVAGE_DEFENSE, ret => gotTarget
                            && SpellManager.HasSpell(SAVAGE_DEFENSE)
                            && GetSpellCooldown(SAVAGE_DEFENSE).TotalSeconds < 1
                            && Me.HealthPercent <= SettingsBear.myPrefs.PercentSavageDefense
                            && Me.RagePercent >= 60),
                        Cast(SURVIVAL_INSTINCTS, ret => gotTarget
                            && SpellManager.HasSpell(SURVIVAL_INSTINCTS)
                            && GetSpellCooldown(SURVIVAL_INSTINCTS).TotalSeconds < 1
                            && Me.HealthPercent <= SettingsBear.myPrefs.PercentSurvivalInstincts),
                        Cast(BERSERK, ret => gotTarget
                            && SpellManager.HasSpell(BERSERK)
                            && GetSpellCooldown(BERSERK).TotalSeconds < 1
                            && IsWoWBoss(Me.CurrentTarget)
                            && Me.CurrentTarget.IsWithinMeleeRange),
                        Cast(FORCE_OF_NATURE, ret => SpellManager.HasSpell(FORCE_OF_NATURE)
                            && gotTarget
                            && UseForceOfNaure),
                        Cast(INCARNATION, ret => gotTarget
                            && SpellManager.HasSpell(INCARNATION)
                            && GetSpellCooldown(INCARNATION).TotalSeconds < 1
                            && IsWoWBoss(Me.CurrentTarget)
                            && Me.CurrentTarget.IsWithinMeleeRange),
                        Trinket1(),
                        Trinket2(),
                        Cast("Lifeblood", ret => gotTarget
                            && SpellManager.HasSpell("Lifeblood")
                            && GetSpellCooldown("Lifeblood").TotalSeconds < 1
                            && IsWoWBoss(Me.CurrentTarget)
                            && Me.CurrentTarget.IsWithinMeleeRange),
                        Cast("Berserking", ret => gotTarget
                            && SpellManager.HasSpell("Berserking")
                            && GetSpellCooldown("Berserking").TotalSeconds < 1
                            && IsWoWBoss(Me.CurrentTarget)
                            && Me.CurrentTarget.IsWithinMeleeRange),
                        Cast(MANGLE, ret => gotTarget
                            && (GetSpellCooldown(MANGLE).TotalSeconds < 1
                            || IsOverlayed(MANGLE_INT))),
                        Cast(MAUL, ret => gotTarget
                            && Me.HasAura(TOOTH_AND_CLAW)
                            && GetSpellCooldown(MAUL).TotalSeconds < 1
                            && Me.RagePercent >= 30),
                        Cast(MAUL, ret => gotTarget
                            && GetSpellCooldown(MAUL).TotalSeconds < 1 && Me.RagePercent >= 70),
                        Cast(THRASH, ret => gotTarget
                            && !PauseAoe
                            && GetSpellCooldown(THRASH).TotalSeconds < 1 && !Me.CurrentTarget.HasAura(THRASH)),
                        Cast(SWIPE, ret => gotTarget
                            && !PauseAoe
                            && GetSpellCooldown(SWIPE).TotalSeconds < 1 && UnfriendlyUnits.Count() > 1),
                        Cast(LACERATE, ret => gotTarget
                            && GetSpellCooldown(LACERATE).TotalSeconds < 1)
                    )));
        }

        #region can buff and eat
        public bool CanBuffEat
        {
            get
            {
                return !Me.Mounted && !Me.IsFlying && !Me.OnTaxi && !Me.IsDead && !Me.IsGhost;
            }
        }
        #endregion

        #region gotTarget
        public bool gotTarget
        {
            get
            {
                return Me.CurrentTarget != null && !Me.CurrentTarget.IsDead && !Me.CurrentTarget.IsFriendly && Me.CurrentTarget.Attackable && Me.CurrentTarget.CanSelect;
            }
        }
        #endregion

        #region spells
        string MAUL = "Maul";
        int MAUL_INT = 6807;
        string LACERATE = "Lacerate";
        string MANGLE = "Mangle";
        int MANGLE_INT = 33878;
        string SWIPE = "Swipe";
        string THRASH = "Thrash";
        string WILD_CHARGE = "Wild Charge";
        string FAERIE_FIRE = "Faerie Fire";
        string FAERIE_SWARM = "Faerie Swarm";
        string FORCE_OF_NATURE = "Force of Nature";
        string DREAM_OF_CENARIUS = "Dream of Cenarius";
        string BERSERK = "Berserk";
        string GROWL = "Growl";
        string BEAR_FORM = "Bear Form";
        string BEAR_HUG = "Bear Hug";
        string HEALING_TOUCH = "Healing Touch";
        int HEALING_TOUCH_INT = 5185;
        string REJUVENATION = "Rejuvenation";
        string SKULL_BASH = "Skull Bash";
        string MIGHTY_BASH = "Mighty Bash";
        string WAR_STOMP = "War Stomp";
        string ENRAGE = "Enrage";
        string CYCLONE = "Cyclone";
        string INCARNATION = "Incarnation";
        string BARKSKIN = "Barkskin";
        string FRENZIED_REGENERATION = "Frenzied Regeneration";
        string SURVIVAL_INSTINCTS = "Survival Instincts";
        string MIGHT_OF_URSOC = "Might of Ursoc";
        string SAVAGE_DEFENSE = "Savage Defense";
        int SAVAGE_DEFENSE_INT = 62606;
        string MOTW = "Mark of the Wild";
        string TOOTH_AND_CLAW = "Tooth and Claw";
        public string REBIRTH = "Rebirth";
        int REBIRTH_INT = 20484;
        
        #endregion

        #region overlayed
        public bool IsOverlayed(int spellID)
        {
            return Lua.GetReturnVal<bool>("return IsSpellOverlayed(" + spellID + ")", 0);
        }
        #endregion overlayed

        #region spellcharges
        public static double GetSpellCharges(int spellID)
        {
            return Lua.GetReturnVal<int>("return GetSpellCharges(" + spellID + ")", 0);
        }
        #endregion

        #region spellcasting
        private delegate T Selection<out T>(object context);
        Composite Cast(string spell, Selection<bool> reqs = null)
        {
            return
                new Decorator(
                    ret => ((reqs != null && reqs(ret)) || (reqs == null)) && SpellManager.CanCast(spell),
                    new Action(ret =>
                    {
                        SpellManager.Cast(spell);
                        Logging.Write(spell);
                    }
                        ));
        }
        Composite CastOnMe(string spell, Selection<bool> reqs = null)
        {
            return
                new Decorator(
                    ret => ((reqs != null && reqs(ret)) || (reqs == null)) && SpellManager.CanCast(spell),
                    new Action(ret =>
                    {
                        SpellManager.Cast(spell, Me);
                        Logging.Write(spell);
                    }
                        ));
        }

        public static TimeSpan GetSpellCooldown(string spell)
        {
            SpellFindResults results;
            if (SpellManager.FindSpell(spell, out results))
            {
                if (results.Override != null)
                    return results.Override.CooldownTimeLeft;
                return results.Original.CooldownTimeLeft;
            }


            return TimeSpan.MaxValue;
        }
        #endregion

        #region addcount
        IEnumerable<WoWUnit> UnfriendlyUnits
        {
            get { return ObjectManager.GetObjectsOfType<WoWUnit>(true, false).Where(u => u != null && !u.IsDead && u.CanSelect && u.Attackable && !u.IsFriendly && u.IsWithinMeleeRange); }
        }
        #endregion

        #region movement targeting facing
        [DllImport("user32.dll")]
        private static extern short GetAsyncKeyState(Keys vKey);

        public bool AllowFacing
        {
            get
            {
                if (SettingsBear.myPrefs.DisableAutoFacing
                    && (Me.GroupInfo.IsInRaid || Me.IsInInstance || Me.GroupInfo.PartyMembers.Count() >= 3))
                {
                    return false;
                }
                if ((GetAsyncKeyState(Keys.LButton) != 0
                    && GetAsyncKeyState(Keys.RButton) != 0) ||
                    GetAsyncKeyState(Keys.W) != 0 ||
                    GetAsyncKeyState(Keys.S) != 0 ||
                    GetAsyncKeyState(Keys.D) != 0 ||
                    GetAsyncKeyState(Keys.A) != 0)
                {
                    return false;
                }
                return SettingsBear.myPrefs.AutoFacing;

            }
        }
        public bool AllowTargeting
        {
            get
            {
                if (SettingsBear.myPrefs.DisableAutoTargeting
                    && (Me.GroupInfo.IsInRaid || Me.IsInInstance || Me.GroupInfo.PartyMembers.Count() > 3))
                {
                    return false;
                }
                if ((GetAsyncKeyState(Keys.LButton) != 0
                    && GetAsyncKeyState(Keys.RButton) != 0) ||
                    GetAsyncKeyState(Keys.W) != 0 ||
                    GetAsyncKeyState(Keys.S) != 0 ||
                    GetAsyncKeyState(Keys.D) != 0 ||
                    GetAsyncKeyState(Keys.A) != 0)
                {
                    return false;
                }
                return SettingsBear.myPrefs.AutoTargeting;
            }
        }
        public bool AllowMovement
        {
            get
            {
                if (SettingsBear.myPrefs.DisableAutoMovement
                    && (Me.GroupInfo.IsInRaid || Me.IsInInstance || Me.GroupInfo.PartyMembers.Count() > 3))
                {
                    return false;
                }
                if ((GetAsyncKeyState(Keys.LButton) != 0
                    && GetAsyncKeyState(Keys.RButton) != 0) ||
                    GetAsyncKeyState(Keys.W) != 0 ||
                    GetAsyncKeyState(Keys.S) != 0 ||
                    GetAsyncKeyState(Keys.D) != 0 ||
                    GetAsyncKeyState(Keys.A) != 0)
                {
                    return false;
                }


                return SettingsBear.myPrefs.AutoMovement;
            }
        }

        Composite CreateMovementBehavior()
        {
            return
                    new Action(ret =>
                    {
                        Navigator.MoveTo(StyxWoW.Me.CurrentTarget.Location);
                        return RunStatus.Failure;
                    }
                );
        }
        Composite CreateStopMovement()
        {
            return new Action(ret =>
            {
                Navigator.PlayerMover.MoveStop();
                return RunStatus.Failure;
            });
        }
        Composite CreateMoveBackBehavior()
        {
            return new Action(ret =>
            {
                WoWMovement.Move(WoWMovement.MovementDirection.Backwards);
                while (gotTarget && Me.CurrentTarget.IsAlive && Me.CurrentTarget.Distance < 10)
                {
                    break;
                }
                Navigator.PlayerMover.MoveStop();
                return RunStatus.Failure;
            });
        }
        float myRange
        {
            get
            {
                if ((Me.CurrentTarget != null && Me.CurrentTarget.IsPlayer)) { return 1.5f; }
                return 3.5f;
            }
        }
        public bool NeedGoBackwards
        {
            get
            {
                return Me.CurrentTarget != null && (Me.CurrentTarget.IsCasting && Me.CurrentTarget.CastingSpell.ToString() == "Blazing Cleave");
            }
        }
        #endregion

        #region facing
        Composite FaceMyTarget()
        {
            return
                new Action(ret =>
                {
                    Me.CurrentTarget.Face();
                    return RunStatus.Failure;
                });
        }
        #endregion

        #region pause
        public static bool PauseAoe = false;
        public static bool Paused = false;

        public static void HandleModifierStateChanged(object sender, LuaEventArgs args)
        {
            if (SettingsBear.myPrefs.StopCRKey == SettingsBear.Keypress.NONE
                && SettingsBear.myPrefs.StopAoeKey == SettingsBear.Keypress.NONE)
            {
                return;
            }
            if (Convert.ToInt32(args.Args[1]) == 1)
            {
                string pauseMyAoe = "AOE cancelled, press " + SettingsBear.myPrefs.StopAoeKey.ToString() + " in WOW again to turn AOE back on";
                if (args.Args[0].ToString() == SettingsBear.myPrefs.StopAoeKey.ToString())
                {
                    PauseAoe = !PauseAoe;
                    if (PauseAoe)
                    {
                        Logging.Write("Aoe cancelled, press {0} in WOW again to resume Aoe",
                                     SettingsBear.myPrefs.StopAoeKey.ToString());
                        if (SettingsBear.myPrefs.PrintRaidstyleMsg)
                            Lua.DoString(
                                "RaidNotice_AddMessage(RaidWarningFrame, \"" + pauseMyAoe + "\", ChatTypeInfo[\"RAID_WARNING\"]);");
                    }
                    else
                    {
                        Logging.Write("Aoe Resumed");
                        if (SettingsBear.myPrefs.PrintRaidstyleMsg)
                            Lua.DoString(
                                "RaidNotice_AddMessage(RaidWarningFrame, \"Aoe Resumed !\", ChatTypeInfo[\"RAID_WARNING\"]);");
                    }
                }
            }
            if (Convert.ToInt32(args.Args[1]) == 1)
            {
                if (args.Args[0].ToString() == SettingsBear.myPrefs.StopCRKey.ToString())
                {
                    string pauseCR = "CR paused, press " + SettingsBear.myPrefs.StopCRKey.ToString() + " in WOW again to turn back on";
                    Paused = !Paused;
                    if (Paused)
                    {
                        Logging.Write("CR paused, press {0} in WOW again to turn back on",
                                     SettingsBear.myPrefs.StopCRKey.ToString());
                        if (SettingsBear.myPrefs.PrintRaidstyleMsg)
                            Lua.DoString(
                                "RaidNotice_AddMessage(RaidWarningFrame, \"" + pauseCR + "\", ChatTypeInfo[\"RAID_WARNING\"]);");
                    }
                    else
                    {
                        Logging.Write("CR running again ....");
                        if (SettingsBear.myPrefs.PrintRaidstyleMsg)
                            Lua.DoString(
                                "RaidNotice_AddMessage(RaidWarningFrame, \"CR running again ....\", ChatTypeInfo[\"RAID_WARNING\"]);");
                    }
                }
            }
        }
        #endregion pause

        #region loot

        private double LootRange
        {
            get { return LootTargeting.LootRadius; }
        }
        private IOrderedEnumerable<WoWUnit> Lootables
        {
            get
            {
                var targetsList = ObjectManager.GetObjectsOfType<WoWUnit>(false, false).Where(
                        p => p.Lootable && p.Distance <= LootRange).OrderBy(l => l.Distance);
                return targetsList;
            }
        }
        private void GetLoot()
        {
            if (Me.IsCasting || Lootables.Count() == 0 || Me.IsMoving)
                return;
            if (LootFrame.Instance != null && LootFrame.Instance.IsVisible)
            {
                LootFrame.Instance.LootAll();
                if (Me.CurrentTarget != null && Me.CurrentTarget.IsDead)
                {
                    Me.ClearTarget();
                }
                return;
            }
            var lootTarget = Lootables.FirstOrDefault();
            if (lootTarget.Distance > lootTarget.InteractRange && !Me.GroupInfo.IsInParty && !Me.GroupInfo.IsInRaid && !Me.IsInInstance)
            {
                Logging.Write("Moving to loot {0}.", lootTarget.Name);
                Navigator.MoveTo(lootTarget.Location);
            }
            else
            {
                lootTarget.Interact();
                if (Me.CurrentTarget != null && Me.CurrentTarget.IsDead)
                {
                    Me.ClearTarget();
                }
                return;
            }
        }
        #endregion loot

        #region FindTarget
        WoWUnit FindTarget()
        {
            WoWUnit myTarget = ObjectManager.GetObjectsOfType<WoWUnit>(true, false).Where(u => ValidUnit(u)
                && u.DistanceSqr <= 8 * 8
                && !Blacklist.Contains(u, BlacklistFlags.All))
                .OrderBy(u => u.IsPlayer)
                .ThenBy(u => u.Distance)
                .FirstOrDefault();
            if (myTarget != null)
            {
                Logging.Write(Colors.PaleGreen, "Found new Target " + myTarget.Name);
                myTarget.Target();
                return myTarget;
            }
            return null;
        }
        #endregion

        #region members to heal
        Composite HealPartyMember()
        {
            return 
                new Action(ret =>
                {
                    var myHealTarget = HealTarget();
                    if (myHealTarget != null && IsOverlayed(HEALING_TOUCH_INT) && myHealTarget.IsAlive)
                    {
                        SpellManager.Cast(HEALING_TOUCH, myHealTarget);
                        Logging.Write(Colors.BlanchedAlmond, "Healing " + myHealTarget.Name + " with Healing Touch proc");
                        return RunStatus.Success;
                    }
                    return RunStatus.Failure;
                });
        }
        public static IEnumerable<WoWPlayer> HealMembers
        {
            get
            {
                ulong[] guids =
                    StyxWoW.Me.GroupInfo.RaidMemberGuids.Union(StyxWoW.Me.GroupInfo.PartyMemberGuids)
                        .Union(new[] { StyxWoW.Me.Guid })
                        .Distinct()
                        .ToArray();

                return (
                    from p in ObjectManager.GetObjectsOfType<WoWPlayer>(true, true)
                    where p.IsFriendly && guids.Any(g => g == p.Guid)
                    select p).ToList();
            }
        }
        public static IEnumerable<WoWPlayer> NearbyHealMembers
        {
            get
            {
                return HealMembers.Where(p => p.DistanceSqr <= 35 * 35)
                    .OrderBy(p => p.HealthPercent)
                    .ThenBy(p => p.Distance)
                    .ToList();
            }
        }
        private static WoWPlayer HealTarget()
        {
            return NearbyHealMembers.FirstOrDefault();
        }
        #endregion members to heal

        #region symbiosis

        Composite CastSymbiosis()
        {
            return new Action(ret =>
                 {
                     WoWPlayer symtarget = SymbiosisTarget();
                     if (symtarget != null && symtarget != StyxWoW.Me)
                     {
                         Symbiosis(symtarget);
                         return RunStatus.Success;
                     }
                     return RunStatus.Failure;
                 });
        }
        public static IEnumerable<WoWPlayer> GroupMembers
        {
            get
            {
                ulong[] guids =
                    StyxWoW.Me.GroupInfo.RaidMemberGuids.Union(StyxWoW.Me.GroupInfo.PartyMemberGuids)
                        .Union(new[] { StyxWoW.Me.Guid })
                        .Distinct()
                        .ToArray();

                return (
                    from p in ObjectManager.GetObjectsOfType<WoWPlayer>(true, true)
                    where p.IsFriendly && guids.Any(g => g == p.Guid)
                    select p).ToList();
            }
        }

        public static IEnumerable<WoWPlayer> NearbyGroupMembers
        {
            get { return GroupMembers.Where(p => p.DistanceSqr <= 30 * 30).ToList(); }
        }


        private static WoWPlayer SymbiosisTarget()
        {
            if (!SpellManager.HasSpell("Symbiosis"))
                return null;
            return NearbyGroupMembers.FirstOrDefault(
                p => IsValidSymbiosisTarget(p) && p.Class == WoWClass.DeathKnight) // Bone Shield
                   ??
                   (NearbyGroupMembers.FirstOrDefault(
                       p => IsValidSymbiosisTarget(p) && p.Class == WoWClass.Paladin) // Consecration
                    ??
                    (NearbyGroupMembers.FirstOrDefault(
                        p => IsValidSymbiosisTarget(p) && p.Class == WoWClass.Shaman) // Lightning Shield
                     ?? (NearbyGroupMembers.FirstOrDefault(
                         p => IsValidSymbiosisTarget(p) && p.Class == WoWClass.Monk) // ElusiveBrew
                         )
                        )
                       );
        }
        private static void Symbiosis(WoWUnit unit)
        {

            if (StyxWoW.Me.CurrentTarget != unit)
            {
                unit.Target();
                return;
            }
            SpellManager.Cast(110309, unit);
            Logging.Write(Colors.ForestGreen, "Casting Symbiosis on " + unit.Name);
            if (StyxWoW.Me.HasAura(110309))
                StyxWoW.Me.ClearTarget();
        }

        public static bool IsValidSymbiosisTarget(WoWPlayer p)
        {
            if (p == null)
                return false;

            if (p.IsHorde != StyxWoW.Me.IsHorde)
                return false;

            if (Blacklist.Contains(p.Guid, BlacklistFlags.Combat))
                return false;

            if (!p.IsAlive)
                return false;

            if (p.Level < 87)
                return false;

            if (p.Combat)
                return false;

            if (p.Distance > 28)
                return false;

            return !p.HasAura("Symbiosis") && p.InLineOfSpellSight;
        }
        #endregion

        #region rooted
        Composite RemoveRooted()
        {
            return
                    new Action(ret =>
                    {
                        Lua.DoString("RunMacroText(\"/Cast !Bear Form\")");
                        return RunStatus.Failure;
                    });
        }
        #endregion

        #region crowdcontrol

        public bool IsCrowdControlledTarget(WoWUnit unit)
        {
            Dictionary<string, WoWAura>.ValueCollection auras = unit.Auras.Values;

            return unit.Fleeing
                || HasAuraWithEffect(unit,
                        WoWApplyAuraType.ModConfuse,
                        WoWApplyAuraType.ModCharm,
                        WoWApplyAuraType.ModFear,
                        WoWApplyAuraType.ModPossess);
        }

        public bool IsCrowdControlledPlayer(WoWUnit unit)
        {
            Dictionary<string, WoWAura>.ValueCollection auras = unit.Auras.Values;

            return unit.Rooted
                || unit.Fleeing
                || HasAuraWithEffect(unit,
                        WoWApplyAuraType.ModConfuse,
                        WoWApplyAuraType.ModCharm,
                        WoWApplyAuraType.ModFear,
                        WoWApplyAuraType.ModDecreaseSpeed,
                        WoWApplyAuraType.ModPacify,
                        WoWApplyAuraType.ModPacifySilence,
                        WoWApplyAuraType.ModPossess,
                        WoWApplyAuraType.ModRoot);
        }

        // this one optimized for single applytype lookup
        public bool HasAuraWithEffect(WoWUnit unit, WoWApplyAuraType applyType)
        {
            return unit.Auras.Values.Any(a => a.Spell != null && a.Spell.SpellEffects.Any(se => applyType == se.AuraType));
        }

        public static bool HasAuraWithEffect(WoWUnit unit, params WoWApplyAuraType[] applyType)
        {
            var hashes = new HashSet<WoWApplyAuraType>(applyType);
            return unit.Auras.Values.Any(a => a.Spell != null && a.Spell.SpellEffects.Any(se => hashes.Contains(se.AuraType)));
        }
        #endregion

        #region autoattack
        Composite AutoAttack()
        {
            return new Action(ret =>
            {
                Lua.DoString("StartAttack()");
                return RunStatus.Failure;
            });
        }
        #endregion

        #region paused pauseAoe
        Composite PauseCR()
        {
            return new Action(ret => 
            { 
                return; 
            });
        }
        #endregion

        #region Kind of target
        public bool IsWoWBoss(WoWUnit mytarget)
        {
            if (StyxWoW.Me.CurrentTarget != null)
            {
                if (StyxWoW.Me.CurrentTarget.CreatureRank == WoWUnitClassificationType.WorldBoss)
                {
                    return true;
                }
                else if (target.IsBoss(mytarget))
                {
                    return true;
                }
                else if (Me.CurrentTarget.MaxHealth >= (100 * 1000000)) { return true; }
                else if (StyxWoW.Me.CurrentTarget.CreatureRank == WoWUnitClassificationType.RareElite
                    && StyxWoW.Me.CurrentTarget.MaxHealth >= (StyxWoW.Me.MaxHealth * 3)
                    && (!StyxWoW.Me.GroupInfo.IsInParty
                    || StyxWoW.Me.GroupInfo.NumPartyMembers <= 3)
                    && !StyxWoW.Me.GroupInfo.IsInRaid
                    && !StyxWoW.Me.IsInInstance)
                {
                    return true;
                }
                else if (StyxWoW.Me.CurrentTarget.CreatureRank == WoWUnitClassificationType.Rare
                    && StyxWoW.Me.CurrentTarget.MaxHealth >= (StyxWoW.Me.MaxHealth * 3)
                    && (!StyxWoW.Me.GroupInfo.IsInParty
                    || StyxWoW.Me.GroupInfo.NumPartyMembers <= 3)
                    && !StyxWoW.Me.GroupInfo.IsInRaid
                    && !StyxWoW.Me.IsInInstance)
                {
                    return true;
                }
                else if (StyxWoW.Me.CurrentTarget.CreatureRank == WoWUnitClassificationType.Elite
                    && StyxWoW.Me.CurrentTarget.MaxHealth >= (StyxWoW.Me.MaxHealth * 3)
                    && (!StyxWoW.Me.GroupInfo.IsInParty
                    || StyxWoW.Me.GroupInfo.NumPartyMembers <= 3)
                    && !StyxWoW.Me.GroupInfo.IsInRaid
                    && !StyxWoW.Me.IsInInstance)
                {
                    return true;
                }
                else if (StyxWoW.Me.CurrentTarget.Name.Contains("Dummy")
                    && !StyxWoW.Me.IsInInstance)
                {
                    return true;
                }
                else if (StyxWoW.Me.CurrentTarget.IsPlayer
                    && !StyxWoW.Me.CurrentTarget.IsFriendly)
                {
                    return true;
                }
            }
            return false;
        }
        #endregion Kind of Target

        #region valid units
        public bool ValidUnit(WoWUnit p)
        {
            if (p == null || !p.IsValid)
                return false;

            // Ignore shit we can't select
            if (!p.CanSelect)
            {
                return false;
            }

            // Ignore shit we can't attack
            if (!p.Attackable)
            {
                return false;
            }

            // Duh
            if (p.IsDead)
            {
                return false;
            }

            // check for enemy players here as friendly only seems to work on npc's
            if (p.IsPlayer)
            {
                WoWPlayer pp = p.ToPlayer();
                if (pp.IsHorde == StyxWoW.Me.IsHorde)
                {
                    return false;
                }

                if (pp.Guid == StyxWoW.Me.CurrentTargetGuid && CanAttackCurrentTarget)
                {
                    return false;
                }

                return true;
            }

            // Ignore friendlies!
            if (p.IsFriendly)
            {
                return false;
            }
            // If it is a pet/minion/totem, lets find the root of ownership chain
            WoWPlayer pOwner = GetPlayerParent(p);

            // ignore if owner is player, alive, and not blacklisted then ignore (since killing owner kills it)
            // .. following .IsMe check to prevent treating quest mob summoned by us that we need to kill as invalid 
            if (pOwner != null && pOwner.IsAlive && !pOwner.IsMe)
            {
                if (!ValidUnit(pOwner))
                {
                    return false;
                }
                if (!Blacklist.Contains(pOwner, BlacklistFlags.Combat))
                {
                    return false;
                }
                if (!StyxWoW.Me.IsPvPFlagged)
                {
                    return false;
                }
            }

            // And ignore critters (except for those ferocious ones) /non-combat pets
            if (p.IsNonCombatPet)
            {
                return false;
            }

            // And ignore critters (except for those ferocious ones) /non-combat pets
            if (p.IsCritter && p.ThreatInfo.ThreatValue == 0 && !p.IsTargetingMyRaidMember)
            {
                return false;
            }
            /*
                        if (p.CreatedByUnitGuid != 0 || p.SummonedByUnitGuid != 0)
                            return false;
            */
            return true;
        }

        public WoWPlayer GetPlayerParent(WoWUnit unit)
        {
            // If it is a pet/minion/totem, lets find the root of ownership chain
            WoWUnit pOwner = unit;
            while (true)
            {
                if (pOwner.OwnedByUnit != null)
                    pOwner = pOwner.OwnedByRoot;
                else if (pOwner.CreatedByUnit != null)
                    pOwner = pOwner.CreatedByUnit;
                else if (pOwner.SummonedByUnit != null)
                    pOwner = pOwner.SummonedByUnit;
                else
                    break;
            }

            if (unit != pOwner && pOwner.IsPlayer)
                return pOwner as WoWPlayer;

            return null;
        }
        public bool CanAttackCurrentTarget
        {
            get
            {
                if (StyxWoW.Me.CurrentTarget == null)
                    return false;

                return Lua.GetReturnVal<bool>("return UnitCanAttack(\"player\",\"target\")", 0);
            }
        }
        #endregion

        #region eatfood
        Composite EatFood()
        {
            return new Decorator(ret => Me.HealthPercent <= SettingsBear.myPrefs.PercentEatFood && CanBuffEat && !Me.GroupInfo.IsInRaid && !Me.IsInInstance,
                new Action(ret =>
                {
                    Styx.CommonBot.Rest.Feed();
                    return RunStatus.Failure;
                }));
        }
        #endregion

        #region force of nature
        public Stopwatch FoNTimer = new Stopwatch();
        public bool UseForceOfNaure
        {
            get
            {
                if (FoNTimer.IsRunning && FoNTimer.ElapsedMilliseconds <= 16000) { return false; }

                if (GetSpellCooldown(FORCE_OF_NATURE).TotalSeconds < 1)
                {
                    FoNTimer.Reset();
                    FoNTimer.Start();
                    return true;
                }
                return false;
            }
        }
        #endregion

        #region rebirth
        
        public static List<WoWPlayer> Tanks
        {
            get
            {
                if (!StyxWoW.Me.GroupInfo.IsInParty)
                    return new List<WoWPlayer>(); ;

                return StyxWoW.Me.GroupInfo.RaidMembers.Where(p => p.HasRole(WoWPartyMember.GroupRole.Tank))
                    .Select(p => p.ToPlayer())
                    .Union(new[] { RaFHelper.Leader })
                    .Where(p => p != null && p.IsDead)
                    .Distinct()
                    .ToList();
            }
        }

        public static List<WoWPlayer> Healers
        {
            get
            {
                if (!StyxWoW.Me.GroupInfo.IsInParty)
                    return new List<WoWPlayer>(); ;

                return StyxWoW.Me.GroupInfo.RaidMembers.Where(p => p.HasRole(WoWPartyMember.GroupRole.Healer))
                    .Select(p => p.ToPlayer()).Where(p => p != null && p.IsDead).ToList();

            }
        }
        public static bool AnyTankNearby
        {
            get
            {
                return Tanks.Any(h => h.IsDead && h.Distance < 40);
            }
        }
        public static bool AnyHealerNearby
        {
            get
            {
                return Healers.Any(h => h.IsDead && h.Distance < 40);
            }
        }
        Composite ResTank()
        {
            return 
                new Action(ret =>
                {
                    var ResTankTarget = Tanks.FirstOrDefault();
                    string msg = " is ressing " + ResTankTarget;
                    if (ResTankTarget != null && SpellManager.CanCast(REBIRTH))
                    {
                        SpellManager.Cast(REBIRTH, ResTankTarget);
                        Logging.Write(Colors.Red, "Ressing Tank " + ResTankTarget);
                        ShowWoWChatMessage(msg);
                        runLua(msg);
                        return RunStatus.Success;
                    }
                    return RunStatus.Failure;

                });
        }
        Composite ResHealer()
        {
            return 
                new Action(ret =>
                {
                    
                    var ResHealTarget = Healers.FirstOrDefault();
                    string msg = " is ressing " + ResHealTarget;
                    if (ResHealTarget != null && SpellManager.CanCast(REBIRTH))
                    {
                        SpellManager.Cast(REBIRTH, ResHealTarget);
                        Logging.Write(Colors.Red, "Ressing Healer " + ResHealTarget);
                        string message = "Ressing " + ResHealTarget;
                        ShowWoWChatMessage(msg);
                        runLua(msg);
                        return RunStatus.Success;
                    }
                    return RunStatus.Failure;
                });
        }
        #endregion

        #region Buff Checks

        public bool buffExists(int Buff, WoWUnit onTarget)
        {
            if (onTarget != null)
            {
                var Results = onTarget.GetAuraById(Buff);
                if (Results != null)
                    return true;
            }
            return false;
        }

        public double buffTimeLeft(int Buff, WoWUnit onTarget)
        {
            if (onTarget != null)
            {
                var Results = onTarget.GetAuraById(Buff);
                if (Results != null)
                {
                    if (Results.TimeLeft.TotalMilliseconds > 0)
                        return Results.TimeLeft.TotalMilliseconds;
                }
            }
            return 0;
        }

        public bool buffExists(string Buff, WoWUnit onTarget)
        {
            if (onTarget != null)
            {
                var Results = onTarget.GetAuraByName(Buff);
                if (Results != null)
                    return true;
            }
            return false;
        }

        public double buffTimeLeft(string Buff, WoWUnit onTarget)
        {
            if (onTarget != null)
            {
                var Results = onTarget.GetAuraByName(Buff);
                if (Results != null)
                {
                    if (Results.TimeLeft.TotalMilliseconds > 0)
                        return Results.TimeLeft.TotalMilliseconds;
                }
            }
            return 0;
        }



        public uint buffStackCount(int Buff, WoWUnit onTarget)
        {
            if (onTarget != null)
            {
                var Results = onTarget.GetAuraById(Buff);
                if (Results != null)
                    return Results.StackCount;
            }
            return 0;
        }
        public uint buffStackCount(string Buff, WoWUnit onTarget)
        {
            if (onTarget != null)
            {
                var Results = onTarget.GetAuraByName(Buff);
                if (Results != null)
                    return Results.StackCount;
            }
            return 0;
        }
        #endregion

        #region Cache Checks
        public IEnumerable<WoWAura> cachedAuras = new List<WoWAura>();
        public IEnumerable<WoWAura> cachedTargetAuras = new List<WoWAura>();
        public void getCachedAuras()
        {
            if (Me.CurrentTarget != null)
                cachedTargetAuras = Me.CurrentTarget.GetAllAuras();
            cachedAuras = Me.GetAllAuras();
        }
        #endregion

        #region Cooldown Checks
        private Dictionary<WoWSpell, long> Cooldowns = new Dictionary<WoWSpell, long>();
        public TimeSpan cooldownLeft(int Spell)
        {
            SpellFindResults Results;
            if (SpellManager.FindSpell(Spell, out Results))
            {
                WoWSpell Result = Results.Override ?? Results.Original;
                if (Cooldowns.TryGetValue(Result, out lastUsed))
                {
                    if (DateTime.Now.Ticks < lastUsed)
                        return Result.CooldownTimeLeft;
                    return TimeSpan.MaxValue;
                }
            }
            return TimeSpan.MaxValue;
        }
        public TimeSpan cooldownLeft(string Spell)
        {
            SpellFindResults Results;
            if (SpellManager.FindSpell(Spell, out Results))
            {
                WoWSpell Result = Results.Override ?? Results.Original;
                if (Cooldowns.TryGetValue(Result, out lastUsed))
                {
                    if (DateTime.Now.Ticks < lastUsed)
                        return Result.CooldownTimeLeft;
                    return TimeSpan.MaxValue;
                }
            }
            return TimeSpan.MaxValue;
        }
        long lastUsed;
        public int lastCast;
        public bool onCooldown(int Spell)
        {
            SpellFindResults Results;
            if (SpellManager.FindSpell(Spell, out Results))
            {
                WoWSpell Result = Results.Override ?? Results.Original;
                if (Cooldowns.TryGetValue(Result, out lastUsed))
                {
                    if (DateTime.Now.Ticks < lastUsed)
                        return Result.Cooldown;
                    return false;
                }
            }
            return false;
        }
        public bool onCooldown(string Spell)
        {
            SpellFindResults Results;
            if (SpellManager.FindSpell(Spell, out Results))
            {
                WoWSpell Result = Results.Override ?? Results.Original;
                if (Cooldowns.TryGetValue(Result, out lastUsed))
                {
                    if (DateTime.Now.Ticks < lastUsed)
                        return Result.Cooldown;
                    return false;
                }
            }
            return false;
        }
        public TimeSpan spellCooldownLeft(int Spell, bool useTracker = false)
        {
            if (useTracker)
                return cooldownLeft(Spell);
            SpellFindResults results;
            if (SpellManager.FindSpell(Spell, out results))
            {
                if (results.Override != null)
                    return results.Override.CooldownTimeLeft;
                return results.Override.CooldownTimeLeft;
            }
            return TimeSpan.MaxValue;
        }
        public TimeSpan spellCooldownLeft(string Spell, bool useTracker = false)
        {
            if (useTracker)
                return cooldownLeft(Spell);
            SpellFindResults results;
            if (SpellManager.FindSpell(Spell, out results))
            {
                if (results.Override != null)
                    return results.Override.CooldownTimeLeft;
                return results.Override.CooldownTimeLeft;
            }
            return TimeSpan.MaxValue;
        }
        public bool spellOnCooldown(int Spell, bool useTracker = false)
        {
            if (useTracker)
                return !onCooldown(Spell);
            SpellFindResults results;
            if (SpellManager.FindSpell(Spell, out results))
                return results.Override != null ? results.Override.Cooldown : results.Original.Cooldown;
            return false;
        }
        public bool spellOnCooldown(string Spell, bool useTracker = false)
        {
            if (useTracker)
                return !onCooldown(Spell);
            SpellFindResults results;
            if (SpellManager.FindSpell(Spell, out results))
                return results.Override != null ? results.Override.Cooldown : results.Original.Cooldown;
            return false;
        }
        #endregion

        #region Debuff Checks

        public bool debuffExists(int Debuff, WoWUnit onTarget)
        {
            if (onTarget != null)
            {
                WoWAura aura = onTarget.GetAllAuras().FirstOrDefault(a => a.SpellId == Debuff && a.CreatorGuid == Me.Guid);
                if (aura != null)
                {
                    return true;
                }
            }
            return false;
        }

        public double debuffTimeLeft(int Debuff, WoWUnit onTarget)
        {
            if (onTarget != null)
            {
                WoWAura aura = onTarget.GetAllAuras().FirstOrDefault(a =>
                    a.SpellId == Debuff
                    && a.CreatorGuid == Me.Guid);

                if (aura == null)
                {
                    return 0;
                }
                return aura.TimeLeft.TotalMilliseconds;
            }
            return 0;
        }

        public uint debuffStackCount(int Debuff, WoWUnit onTarget)
        {
            if (onTarget != null)
            {
                WoWAura aura = onTarget.GetAllAuras().FirstOrDefault(a =>
                    a.SpellId == Debuff
                    && a.CreatorGuid == Me.Guid);

                if (aura == null)
                {
                    return 0;
                }
                return aura.StackCount;
            }
            return 0;
        }
        public bool debuffExists(string Debuff, WoWUnit onTarget)
        {
            if (onTarget != null)
            {
                WoWAura aura = onTarget.GetAllAuras().FirstOrDefault(a => a.Name == Debuff && a.CreatorGuid == Me.Guid);
                if (aura != null)
                {
                    return true;
                }
            }
            return false;
        }

        public double debuffTimeLeft(string Debuff, WoWUnit onTarget)
        {
            if (onTarget != null)
            {
                WoWAura aura = onTarget.GetAllAuras().FirstOrDefault(a =>
                    a.Name == Debuff
                    && a.CreatorGuid == Me.Guid);

                if (aura == null)
                {
                    return 0;
                }
                return aura.TimeLeft.TotalMilliseconds;
            }
            return 0;
        }

        public uint debuffStackCount(string Debuff, WoWUnit onTarget)
        {
            if (onTarget != null)
            {
                WoWAura aura = onTarget.GetAllAuras().FirstOrDefault(a =>
                    a.Name == Debuff
                    && a.CreatorGuid == Me.Guid);

                if (aura == null)
                {
                    return 0;
                }
                return aura.StackCount;
            }
            return 0;
        }
        #endregion

        #region useitems
        private static bool CanUseEquippedItem(WoWItem item)
        {
            // Check for engineering tinkers!
            string itemSpell = Lua.GetReturnVal<string>("return GetItemSpell(" + item.Entry + ")", 0);
            if (string.IsNullOrEmpty(itemSpell))
                return false;


            return item.Usable && item.Cooldown <= 0;
        }

        Composite Trinket1()
        {
            return
                new Decorator(ret => gotTarget && Me.Combat && SettingsBear.myPrefs.AutoTrinket1 && (Me.CurrentTarget != null && Me.CurrentTarget.IsWithinMeleeRange),
                    new Action(ret =>
                    {
                        var firstTrinket = StyxWoW.Me.Inventory.Equipped.Trinket1;

                        if (SettingsBear.myPrefs.trinket1hppercent > 0
                            && Me.ManaPercent <= SettingsBear.myPrefs.trinket1hppercent
                            && firstTrinket != null
                            && CanUseEquippedItem(firstTrinket))
                        {
                            firstTrinket.Use();
                            return RunStatus.Success;
                        }
                        if (SettingsBear.myPrefs.trinket1crowdcontrolled
                            && IsCrowdControlledPlayer(Me)
                            && firstTrinket != null
                            && CanUseEquippedItem(firstTrinket))
                        {
                            firstTrinket.Use();
                            return RunStatus.Success;
                        }
                        if (SettingsBear.myPrefs.trinket1dpsboost
                            && firstTrinket != null
                            && CanUseEquippedItem(firstTrinket))
                        {
                            firstTrinket.Use();
                            return RunStatus.Success;
                        }
                        return RunStatus.Failure;
                    }));
        }
        Composite Trinket2()
        {
            return
                new Decorator(ret => gotTarget && Me.Combat && SettingsBear.myPrefs.AutoTrinket2 && (Me.CurrentTarget != null && Me.CurrentTarget.IsWithinMeleeRange),
                    new Action(ret =>
                    {
                        var secondTrinket = StyxWoW.Me.Inventory.Equipped.Trinket2;

                        if (SettingsBear.myPrefs.trinket2hppercent > 0
                            && Me.ManaPercent <= SettingsBear.myPrefs.trinket2hppercent
                            && secondTrinket != null
                            && CanUseEquippedItem(secondTrinket))
                        {
                            secondTrinket.Use();
                            return RunStatus.Success;
                        }
                        if (SettingsBear.myPrefs.trinket2crowdcontrolled
                            && IsCrowdControlledPlayer(Me)
                            && secondTrinket != null
                            && CanUseEquippedItem(secondTrinket))
                        {
                            secondTrinket.Use();
                            return RunStatus.Success;
                        }
                        if (SettingsBear.myPrefs.trinket2dpsboost
                            && secondTrinket != null
                            && CanUseEquippedItem(secondTrinket))
                        {
                            secondTrinket.Use();
                            return RunStatus.Success;
                        }
                        return RunStatus.Failure;
                    }));
        }
        Composite Healthstone()
        {
            return new Decorator(ret => Me.Combat && Me.HealthPercent <= SettingsBear.myPrefs.PercentHealthstone,
                new Action(ret =>
                {
                    var hstone = ObjectManager.GetObjectsOfType<WoWItem>().FirstOrDefault(item => item.Entry == 5512);
                    if (hstone != null && hstone.Usable)
                    {
                        hstone.Use();
                        Logging.Write("Using Healthstone");
                        return RunStatus.Success;
                    }
                    return RunStatus.Failure;
                }));
        }
        Composite AlchemyFlask()
        {
            return new Decorator(
                new Action(ret =>
                {
                    var alchflask = ObjectManager.GetObjectsOfType<WoWItem>().FirstOrDefault(item => item.Entry == 75525);
                    if (alchflask != null && alchflask.Usable && alchflask.Cooldown <= 0)
                    {
                        alchflask.Use();
                        return RunStatus.Success;
                    }
                    return RunStatus.Failure;
                }));
        }
        Composite CrystalOfInsanity()
        {
            return new Action(ret =>
            {
                var crystal = ObjectManager.GetObjectsOfType<WoWItem>().FirstOrDefault(item => item.Entry == 86569);
                if (crystal != null && crystal.Usable && crystal.Cooldown <= 0)
                {
                    crystal.Use();
                    return RunStatus.Success;
                }
                return RunStatus.Failure;
            });
        }
        #endregion

        #region chatmessages
        static string[] chatTypeIds = { "SAY", "EMOTE", "YELL", "PARTY", "GUILD", "OFFICER", "RAID", "RAID_WARNING", "BATTLEGROUND", "WHISPER", "CHANNEL", "AFK", "DND" };

        static public void SendChatMessage(string msg, string chatType = "SAY", string language = null, string channel = null)
        {
            if (msg == null) throw new ArgumentException("Message must be set.");
            if (msg.Length > 255) throw new ArgumentException("Message must be < 255 characters");

            if (chatType != null && !chatTypeIds.Any(chatType.Contains))
            {
                throw new ArgumentException("chatType must be one of " + String.Join(", ", chatTypeIds));
            }


            string[] reqChatType = { "CHANNEL", "WHISPER" };
            if (chatType != null && reqChatType.Any(chatType.Contains) && channel == null)
            {
                throw new ArgumentException(" channel is required for the CHANNEL/WHISPER chat types ");
            }

            runLua(string.Format("SendChatMessage({0}, {1}, {2}, {3});",
                a(msg),
                a(chatType),
                a(language),
                a(channel)
                ));
        }

        static private void runLua(String cmd)
        {
            Lua.DoString(cmd);
        }


        static private String a(String arg)
        {
            // for function calls just return it.
            if (arg != null && arg.IndexOfAny("()".ToCharArray()) != -1)
            {
                return arg;
            }
            // for numbers.
            int i;
            if (arg != null && int.TryParse(arg, out i))
            {
                return arg;
            }

            // strings
            return arg == null ? "nil" : "\"" + arg + "\"";
        }

        static public String cs(String s)
        {
            return s == "" ? null : s;
        }


        public void ShowWoWChatMessage(string message)
        {
            //if (chatMessage == true)
            //{
            Lua.DoString("getglobal(\"ChatFrame1\"):AddMessage(\"|cff2dbbc4" + StyxWoW.Me.Name + " :|cffffffff " + message + "\",\"SAY\", 0, 0, 0);");
            //}

        }
        #endregion
    }
}
